﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using DissipativeInputProcessing;
using System.Drawing;
using AviFile;
using HorizontalAlignment = System.Windows.HorizontalAlignment;
using ListViewItem = System.Windows.Controls.ListViewItem;
using MessageBox = System.Windows.MessageBox;
using Timer = System.Windows.Forms.Timer;

namespace ComputationVisualizer
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Messages

        private const string EmptyFramePoolMsg = "Список кадров пуст.";

        #endregion

        private IFramePool _framePool;
        //поток заполнения списка кадров
        private Task _addingTask;
        private CancellationTokenSource _cancelTokenSource;

        #region Main Grid Stuff

        private void GridSplitter_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (Math.Abs(paletteGridRow.Height.Value - 0.0) < 0.0001)
                paletteGridRow.Height = (GridLength) paletteGridRow.Tag;
            else
            {
                paletteGridRow.Tag = paletteGridRow.Height;
                paletteGridRow.Height = new GridLength(0.0f, GridUnitType.Star);

            }
        }

        private void GridSplitter_MouseDoubleClick_1(object sender, MouseButtonEventArgs e)
        {
            if (Math.Abs(mainGridCadresClmn.Width.Value - 0.0) < 0.0001)
                mainGridCadresClmn.Width = (GridLength) mainGridCadresClmn.Tag;
            else
            {
                mainGridCadresClmn.Tag = mainGridCadresClmn.Width;
                mainGridCadresClmn.Width = new GridLength(0.0f, GridUnitType.Star);
            }
        }

        #endregion

        public MainWindow()
        {
            InitializeComponent();
            _framePool = FramePoolFactory.Instance.CreateStub();
            commonPaletteControl.FramePool = _framePool;
            commonPaletteControl.PaletteUpdated += commonPaletteControl_PaletteUpdated;
        }

        #region Common commands

        private void CloseCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            Close();
        }

        private void CloseCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void OpenCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            var dlg = new FolderBrowserDialog();
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                var folder = dlg.SelectedPath;
                if (_addingTask != null && _cancelTokenSource != null &&
                    _addingTask.Status != TaskStatus.RanToCompletion)
                    _cancelTokenSource.Cancel();
                _cancelTokenSource = new CancellationTokenSource();
                _addingTask = Task.Factory.StartNew(() => AssignFolder(folder, _cancelTokenSource.Token),
                                                    _cancelTokenSource.Token);
            }
        }

        private void OpenCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            var dialog = new OpenFileDialog();
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                if (_addingTask != null && _cancelTokenSource != null &&
                    _addingTask.Status != TaskStatus.RanToCompletion)
                    _cancelTokenSource.Cancel();
                _cancelTokenSource = new CancellationTokenSource();
                _addingTask = Task.Factory.StartNew(() => AssignFile(dialog.FileName, _cancelTokenSource.Token),
                                                    _cancelTokenSource.Token);
            }
        }

        private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        #endregion

        #region Assigning Data Sources
        private void AssignFolder(string folder, CancellationToken ct)
        {
            try
            {
                UpdateUIBeforeAssigning();
                AssignPool(FramePoolFactory.Instance.CreateFramePool(new DirectoryInfo(folder)));
                UpdateUIAfterAssigning(ct);
            }
            catch (IOException ex)
            {
                MessageBox.Show(ex.Message + '\n' + ex.Source);
            }
            catch (Exception)
            {
                MessageBox.Show("Не удалось прочитать файл.");
            }
        }

        private void AssignFile(string fileName, CancellationToken ct)
        {
            try
            {
                UpdateUIBeforeAssigning();
                AssignPool(FramePoolFactory.Instance.CreateFramePool(new FileInfo(fileName)));
                UpdateUIAfterAssigning(ct);
            }
            catch (IOException)
            {
                MessageBox.Show("Не удалось прочитать файл.");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message + '\n' + ex.Source);
            }
        }

        private void AssignPool(IFramePool newPool)
        {
            _framePool = newPool;
            Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
                                                                            {
                                                                                player.SetDataSource(
                                                                                    (index) =>
                                                                                    BitmapConverter.ToBitmapSource(
                                                                                        _framePool.GetFrame(index).Image),
                                                                                    _framePool.Frames.Count);
                                                                                commonPaletteControl.FramePool =
                                                                                    _framePool;
                                                                            }));
        }

        private void UpdateUIBeforeAssigning()
        {
            Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
                                                                 {
                                                                     player.PlayerModel.StopPlaying();
                                                                     loadingLabel.Content = "Загрузка...";
                                                                 }));
        }

        private void UpdateUIAfterAssigning(CancellationToken ct)
        {
            Dispatcher.Invoke(DispatcherPriority.Background, new Action(() => framesListView.Items.Clear()));
            Action<IFrame> looplambda = (frame) =>
            {
                var item = new FrameItem { Frame = frame };
                var i = new System.Windows.Controls.ListViewItem();
                i.Selected += (sender, e) => ((FrameItem)i.Content).SetContentImage();
                i.Unselected += (sender, e) => ((FrameItem)i.Content).SetFrameImage();
                i.Content = item;
                framesListView.Items.Add(i);
            };
            foreach (var frame in _framePool.Frames)
            {
                Dispatcher.Invoke(DispatcherPriority.Background, looplambda, frame);
                //проверка, не отменили ли задание
                if (ct.IsCancellationRequested)
                {
                    Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>loadingLabel.Content = null));
                    ct.ThrowIfCancellationRequested();
                }
            }
            var count = _framePool.Frames.Count;
            Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
            {
                loadingLabel.Content = null;
            }));
        }
        #endregion

        #region UI Updates

        private void framesListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (framesListView.SelectedIndex != -1)
            {
                player.PlayerModel.CurrentTimeValue = framesListView.SelectedIndex;
                commonPaletteControl.CurrentFrame = ((FrameItem) ((ListViewItem)framesListView.SelectedItem).Content).Frame;
            }
            else
                commonPaletteControl.CurrentFrame = null;
        }


        void commonPaletteControl_PaletteUpdated(object sender, EventArgs e)
        {
            if(framesListView.SelectedItem != null)
            {
                var item = (ListViewItem) framesListView.SelectedItem;
                ((FrameItem) item.Content).UpdateImage();
                player.PlayerModel.CurrentTimeValue = framesListView.SelectedIndex;
            }
        }

        #endregion

        #region Export
        private void imagesExprtMenuItem_Click(object sender, RoutedEventArgs e)
        {
            if (_framePool.Frames.Count != 0)
            {
                var dialog = new FolderBrowserDialog();
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    foreach (var frame in _framePool.Frames)
                    {
                        frame.Image.Save(dialog.SelectedPath + "\\" + frame.Description + ".jpg", ImageFormat.Jpeg);
                    }
                }
            }
            else
            {
                MessageBox.Show(EmptyFramePoolMsg);
            }
        }

        private void videoExprtMenuItem_Click(object sender, RoutedEventArgs e)
        {
            if (_framePool.Frames.Count > 0)
            {
                var expWindow = new VideoExportingWindow();
                expWindow.Frames = _framePool;
                if(expWindow.ShowDialog()==true)
                {
                    Task.Factory.StartNew(() =>
                                              {
                                                  Dispatcher.Invoke(DispatcherPriority.Background,
                                                                    new Action(
                                                                        () => loadingLabel.Content = "Экспорт видео..."));
                                                  expWindow.Export();
                                                  Dispatcher.Invoke(DispatcherPriority.Background,
                                                                    new Action(() => loadingLabel.Content = null));
                                              });
                }
            }
            else
                MessageBox.Show(EmptyFramePoolMsg);
        }
        #endregion
    }
}
